230. 二叉搜索树中第K小的元素

230. 二叉搜索树中第K小的元素

Similar Question

leading to the advanced question

Solution Tips

方案一: 中序迭代

迭代法可以提前退出, 不用遍历全部节点

var kthSmallest = function(root, k) {
    // 迭代中序试试

    const queue = [root];
    let cur = root;
    let index = 0;

    while (cur || queue.length) {
        while (cur) {
            queue.push(cur);
            cur = cur.left;
        }

        cur = queue.pop();
        index++;
        if (index === k) return cur.val;
        cur = cur.right;
    }

    return;
};

方法二: 记录子树的节点数

pCE2TPS.png

本质上就是利用了 BST 的性质

var kthSmallest = function(root, k) {
    const bst = new MyBst(root);
    return bst.kthSmallest(k);
};

class MyBst {
    constructor(root) {
        this.root = root;
        this.nodeNum = new Map();
        this.countNode(root);
    }

    // 返回二叉搜索树中第k小的元素
    kthSmallest(k) {
        let node = this.root;
        while (node != null) {
            const left = this.getNodeNum(node.left);
            if (left < k - 1) {
                node = node.right;
                // 在右子树寻找, 需要减去所有比右子树 root 小的元素
				// 与单纯的递归法思路类似
                k = k - (left + 1);
            } else if (left === k - 1) {
                break;
            } else {
                node = node.left;
            }
        }
        return node.val;
    }

    /**
     * 统计以node为根结点的子树的结点数
     */
    countNode(node) {
        if (node == null) {
            return 0;
        }
        this.nodeNum.set(node, 1 + this.countNode(node.left) + this.countNode(node.right));
        return this.nodeNum.get(node);
    }

    /**
     * 统计以node为根结点的子树的结点数
     */
    getNodeNum(node) {
        return this.nodeNum.get(node) || 0;
    }
}

方案三: AVL 数 Search Top K

法 2 可以理解成是法 3 的前置知识。因为是要搭配使用的。在常见的业务要求增删改查都要的话。法 2 + 法 3 配合使用就全是 logn 级别的复杂度。数组的增删复杂度高。也是树形结构本身的优点来的。